/* Copyright 2020 Huawei Device Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author: sxc
 * Date  : 2023.12.6
 *
 */
#include "device_resource_if.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "gpio_if.h"

#define HDF_LOG_TAG led_drv

#define LED_RGB_WRITE  7
#define LED_R_BIT 0x01
#define LED_G_BIT 0x02
#define LED_B_BIT 0x04

struct led_config {
    uint32_t  led_ver;
    uint32_t  led_R;
    uint32_t  led_G;
    uint32_t  led_B;
};
struct led_config g_ledcfg = {0};
/*
GpioRead：      读管脚电平值
GpioWrite：     写管脚电平值
GpioSetDir：    设置管脚方向
GpioGetDir：    获取管脚方向
GpioSetIrq：    设置管脚对应的中断服务函数
GpioUnsetIrq：  取消管脚对应的中断服务函数
GpioEnableIrq： 使能管脚中断
GpioDisableIrq：禁止管脚中断
*/
// 实际处理代码
static int32_t LedGpioCtrl(uint16_t gpio, int32_t mode)
{
    uint16_t level = GPIO_VAL_HIGH;  //default to High/ON

    if (HDF_SUCCESS != GpioSetDir(gpio, GPIO_DIR_OUT)) {
        HDF_LOGE("LedGpioCtrl: GpioSetDir NG");
        return HDF_FAILURE;
    }

	if (mode == 1) {                           //1-On
		level = GPIO_VAL_HIGH;
    } else if (mode == 0) {                    //0-Off
		level = GPIO_VAL_LOW;
    } else {//if (mode == -1) {                //-1-flip
        GpioRead(gpio, &level);
        level = (level+1)&0x01;
    }

    if (HDF_SUCCESS != GpioWrite(gpio, level)) {
        HDF_LOGE("LedGpioCtrl: GpioWrite NG");
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}
//ret = serv->dispatcher->Dispatch(&serv->object, LED_RGB_WRITE, data, NULL)
int32_t LedDriverDispatch(struct HdfDeviceIoClient *client, int32_t cmdId, struct HdfSBuf *dataBuf, struct HdfSBuf *replyBuf)
{
    int32_t result  = HDF_FAILURE;
    int32_t LedMode = -1;

    if (client == NULL || client->device == NULL) {
        HDF_LOGE("Led driver device is NULL");
        return HDF_ERR_INVALID_OBJECT;
    }

    if (g_ledcfg.led_ver != 2) {
        HDF_LOGE("Led driver g_ledcfg.led_ver NOT match");
        return HDF_FAILURE;
    }

    switch (cmdId)
	{
    case LED_RGB_WRITE:
        // 共享内存dataBuf中读取并赋值给LedMode
        result = HdfSbufReadInt32(dataBuf, &LedMode);
        if (result) {
            HDF_LOGI("LedDriverDispatch/RGB: LedMode[0x%{public}X][%{public}s%{public}s%{public}s]",
			          LedMode, (LedMode&LED_R_BIT)?"R":"-", (LedMode&LED_G_BIT)?"G":"-", (LedMode&LED_B_BIT)?"B":"-");

            LedGpioCtrl(g_ledcfg.led_R, (LedMode&LED_R_BIT)?1:0);
            LedGpioCtrl(g_ledcfg.led_G, (LedMode&LED_G_BIT)?1:0);
            LedGpioCtrl(g_ledcfg.led_B, (LedMode&LED_B_BIT)?1:0);
        }
        break;

    default:
		HDF_LOGE("LedDriverDispatch: receiving unknown cmdId, NG!!");
        break;
    }
    return result;
}

int32_t HdfLedDriverBind(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        HDF_LOGE("HDF_INIT(g_ledDriverEntry): HdfLedDriverBind: NG!");
        return HDF_ERR_INVALID_OBJECT;
    }

    static struct IDeviceIoService ledDriverServ = {
        .Dispatch = LedDriverDispatch,
    };
    // 绑定LedDriverDispatch函数至deviceObject->service，处理用户态发下来的消息
    deviceObject->service = (struct IDeviceIoService *)(&ledDriverServ);
    HDF_LOGI("HDF_INIT(g_ledDriverEntry): HdfLedDriverBind: OK! NodeName[%{public}s]", deviceObject->property->name);

    return HDF_SUCCESS;
}

int32_t HdfLedDriverInit(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        HDF_LOGE("HDF_INIT(g_ledDriverEntry): HdfLedDriverInit: NG!");
        return HDF_ERR_INVALID_OBJECT;
    }

    struct DeviceResourceIface *CfgOps = NULL;
    CfgOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);

    if (CfgOps == NULL || CfgOps->GetUint32 == NULL) {
        HDF_LOGE("%s: invalid CfgOps fail!", __func__);
        return HDF_FAILURE;
    }
    // 获取hcs配置中的参数，如led_version已在//sample/hello/hcs/led_config_rk3568.hcs中配置
    if(CfgOps->GetUint32(deviceObject->property, "led_version", &g_ledcfg.led_ver, 0) != HDF_SUCCESS) {
        HDF_LOGE("%s: read led_version fail!", __func__);
        return HDF_FAILURE;
    }
    if(CfgOps->GetUint32(deviceObject->property, "led_R", &g_ledcfg.led_R, 0) != HDF_SUCCESS) {
        g_ledcfg.led_ver = 0;
        HDF_LOGE("%s: read led_R fail!", __func__);
        return HDF_FAILURE;
    }
    if(CfgOps->GetUint32(deviceObject->property, "led_G", &g_ledcfg.led_G, 0) != HDF_SUCCESS) {
        g_ledcfg.led_ver = 0;
        HDF_LOGE("%s: read led_G fail!", __func__);
        return HDF_FAILURE;
    }
    if(CfgOps->GetUint32(deviceObject->property, "led_B", &g_ledcfg.led_B, 0) != HDF_SUCCESS) {
        g_ledcfg.led_ver = 0;
        HDF_LOGE("%s: read led_B fail!", __func__);
        return HDF_FAILURE;
    }

    HDF_LOGI("HDF_INIT(g_ledDriverEntry): HdfLedDriverInit: OK!");
    return HDF_SUCCESS;
}

void HdfLedDriverRelease(struct HdfDeviceObject *deviceObject)
{
    if (deviceObject == NULL) {
        HDF_LOGE("HDF_INIT(g_ledDriverEntry): HdfLedDriverRelease: NG!");
        return;
    }

    HDF_LOGI("HDF_INIT(g_ledDriverEntry): HdfLedDriverRelease: OK!");
    return;
}

struct HdfDriverEntry g_ledDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "led_driver",
    .Bind = HdfLedDriverBind,
    .Init = HdfLedDriverInit,
    .Release = HdfLedDriverRelease,
};
/* 调用HDF_INIT将驱动入口注册到HDF框架中，在加载驱动时HDF框架会先调用Bind函数，
   再调用Init函数加载该驱动。当Init调用异常时，HDF框架会调用Release释放驱动资源并退出 */
HDF_INIT(g_ledDriverEntry);
